﻿//PlazaColumnList.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Plaza.Metadata
{
	using System;
	using System.Collections.Generic;
	using System.Linq;

	using Ecng.Collections;
	using Ecng.Common;

	/// <summary>
	/// Коллекция колонок с метаданными.
	/// </summary>
	public sealed class PlazaColumnList : SynchronizedSet<PlazaColumn>
	{
		private readonly SynchronizedSet<PlazaColumn> _nonMandatoryColumns = new SynchronizedSet<PlazaColumn>();

		internal PlazaColumnList()
		{
		}

		private PlazaTable _table;

		internal PlazaTable Table
		{
			get { return _table; }
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				foreach (var column in this)
				{
					CheckColumnTable(column, value);
				}

				_table = value;
			}
		}

		internal PlazaColumn ReplId { get; private set; }
		internal PlazaColumn ReplRevision { get; private set; }
		internal PlazaColumn ReplAction { get; private set; }

		internal IEnumerable<PlazaColumn> NonMandatoryColumns
		{
			get { return _nonMandatoryColumns; }
		}

		/// <summary>
		/// Найти колонку по текстовому названию.
		/// </summary>
		/// <param name="name">Название колонки.</param>
		/// <returns>Найденная колонка. Если колонка не найдена, то будет возвращено значение null.</returns>
		public PlazaColumn this[string name]
		{
			get { return this.FirstOrDefault(c => c.Name == name); }
		}

		internal IEnumerable<string> Names
		{
			get { return this.Select(x => x.Name); }
		}

		/// <summary>
		/// Вызывается при добавлении колонки в конец списка.
		/// </summary>
		/// <param name="column">Колонка.</param>
		/// <returns>True, если колонку можно добавить. Иначе, false.</returns>
		protected override bool OnAdding(PlazaColumn column)
		{
			if (column == null)
				throw new ArgumentNullException("column");

			if (column.Index != -1)
				throw new ArgumentException("Колонка {0} уже имеет индекс.".Put(column.Name), "column");

			if (Contains(column))
				throw new ArgumentException("Колонка {0} уже добавлена.".Put(column.Name), "column");

			if (Table != null)
				CheckColumnTable(column, Table);

			if (!column.IsMandatory)
				_nonMandatoryColumns.Add(column);

			column.Index = Count;

			switch (column.Name)
			{
				case "replID":
					ReplId = column;
					break;
				case "replRev":
					ReplRevision = column;
					break;
				case "replAct":
					ReplAction = column;
					break;
			}

			return base.OnAdding(column);
		}

		/// <summary>
		/// Вызывается при удалении всех колонок из списка.
		/// </summary>
		/// <returns>True, если можно удалить все колонки. Иначе, false.</returns>
		protected override bool OnClearing()
		{
			throw new NotSupportedException("Нельзя удалять все колонки.");
		}

		/// <summary>
		/// Вызывается при удалении колонки.
		/// </summary>
		/// <param name="column">Колонка.</param>
		/// <returns>True, если колонку можно удалить. Иначе, false.</returns>
		protected override bool OnRemoving(PlazaColumn column)
		{
			if (column == null)
				throw new ArgumentNullException("column");

			if (column.IsMandatory)
				throw new ArgumentException("Нельзя удалять обязательную колонку {0}.".Put(column.Name));

			_nonMandatoryColumns.Remove(column);

			foreach (var c in this)
			{
				if (c.Index > column.Index)
					c.Index--;
			}

			column.Index = -1;

			return base.OnRemoving(column);
		}

		/// <summary>
		/// Вызывается при включении колонки в список.
		/// </summary>
		/// <param name="index">Индекс.</param>
		/// <param name="column">Колонка.</param>
		/// <returns>True, если колонку можно вставить. Иначе, false.</returns>
		protected override bool OnInserting(int index, PlazaColumn column)
		{
			if (Contains(column))
				throw new ArgumentException("Колонка {0} уже добавлена.".Put(column.Name), "column");

			if (Table != null)
				CheckColumnTable(column, Table);

			if (!column.IsMandatory)
				_nonMandatoryColumns.Add(column);

			foreach (var c in this)
			{
				if (c.Index >= column.Index)
					c.Index++;
			}

			return base.OnInserting(index, column);
		}

		private static void CheckColumnTable(PlazaColumn column, PlazaTable table)
		{
			if (column == null)
				throw new ArgumentNullException("column");

			if (column.TableName != table.Name)
				throw new ArgumentException("Колонка {0} относиться к таблице {1}, в то время как сама таблица имеет системное имя {2}.".Put(column.Name, column.TableName, table.Name));
		}
	}
}